Namespace Utility

    ''' <summary>
    ''' FTP command class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class FTP

        Public Const CST_URI_PORT As Integer = 21
        Private Shared m_Timeout As Integer

        Private m_UriBuilder As UriBuilder

        ''' <summary>
        ''' File item king enum.
        ''' </summary>
        ''' <remarks></remarks>
        Public Enum FileSystemItemKind
            File = 0
            Directory = 1
        End Enum

        ''' <summary>
        ''' File item access enum.
        ''' </summary>
        ''' <remarks></remarks>
        Public Enum FileSystemItemAccess
            None = 0
            Read = 1
            Write = 2
            Execute = 4
        End Enum

#Region " Uri Properties "

        ''' <summary>
        ''' Get current Uri.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Uri() As Uri
            Get
                Return Me.m_UriBuilder.Uri
            End Get
            Set(ByVal value As Uri)
                Me.m_UriBuilder = New UriBuilder(value)
            End Set
        End Property

        ''' <summary>
        ''' Get ot set FTP server host.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Host() As String
            Get
                Return Me.m_UriBuilder.Host
            End Get
            Set(ByVal value As String)
                Me.m_UriBuilder.Host = value
            End Set
        End Property

        ''' <summary>
        ''' Get or set FTP server port.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>Default value: 21.</remarks>
        Public Property Port() As Integer
            Get
                Return Me.m_UriBuilder.Port
            End Get
            Set(ByVal value As Integer)
                Me.m_UriBuilder.Port = value
            End Set
        End Property

        ''' <summary>
        ''' Login user name of FTP server.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property UserName() As String
            Get
                Return Me.m_UriBuilder.UserName
            End Get
            Set(ByVal value As String)
                Me.m_UriBuilder.UserName = value
            End Set
        End Property

        ''' <summary>
        ''' Login password of FTP server.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Password() As String
            Get
                Return Me.m_UriBuilder.Password
            End Get
            Set(ByVal value As String)
                Me.m_UriBuilder.Password = value
            End Set
        End Property

#End Region

        ''' <summary>
        ''' Get or set timeout in second.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Property Timeout() As Integer
            Get
                Return m_Timeout
            End Get
            Set(ByVal value As Integer)
                m_Timeout = value
            End Set
        End Property

        ''' <summary>
        ''' Get current path.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Path() As String
            Get
                Return Me.GetPathString
            End Get
        End Property

        ''' <summary>
        ''' Get files and directories in current path.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Items() As FileSystemItem()
            Get
                Return Me.GetFileItems.ToArray()
            End Get
        End Property

#Region " File System Item Inner Class "

        ''' <summary>
        ''' FTP File and directory class.
        ''' </summary>
        ''' <remarks></remarks>
        Public Class FileSystemItem

            Private m_Name As String
            Private m_Kind As FileSystemItemKind
            Private m_Length As Long
            Private m_accUsr, m_accGrp, m_accAll As FileSystemItemAccess
            Private m_timeStamp As DateTime
            Private m_User As String
            Private m_Group As String
            Private m_Attributes As String

#Region " Properties "

            ''' <summary>
            ''' Get the name of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Name() As String
                Get
                    Return Me.m_Name
                End Get
            End Property

            ''' <summary>
            ''' Get the kind of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks>File or Directory.</remarks>
            Public ReadOnly Property Kind() As FileSystemItemKind
                Get
                    Return Me.m_Kind
                End Get
            End Property

            ''' <summary>
            ''' Get the access of self user of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property UserAccess() As FileSystemItemAccess
                Get
                    Return Me.m_accUsr
                End Get
            End Property

            ''' <summary>
            ''' Get the access of current group of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property GroupAccess() As FileSystemItemAccess
                Get
                    Return Me.m_accGrp
                End Get
            End Property

            ''' <summary>
            ''' Get the access of all users of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property GlobalAccess() As FileSystemItemAccess
                Get
                    Return Me.m_accAll
                End Get
            End Property

            ''' <summary>
            ''' Get the time stamp of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property [Date]() As DateTime
                Get
                    Return Me.m_timeStamp
                End Get
            End Property

            ''' <summary>
            ''' Get the time stamp of file or directory in string format.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks>Format: yyyy-MM-dd HH:mm:ss</remarks>
            Public ReadOnly Property DateString() As String
                Get
                    Return Me.m_timeStamp.ToString("yyyy-MM-dd HH:mm:ss")
                End Get
            End Property

            ''' <summary>
            ''' Get the size of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Length() As Long
                Get
                    Return Me.m_Length
                End Get
            End Property

            ''' <summary>
            ''' Get the owner user name of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property OwnerUser() As String
                Get
                    Return Me.m_User
                End Get
            End Property

            ''' <summary>
            ''' Get the owner group name of file or directory.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property OwnerGroup() As String
                Get
                    Return Me.m_Group
                End Get
            End Property

            ''' <summary>
            ''' Get the attributs string.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks>The attributes string is showed such as 'drwxr--r--'.</remarks>
            Public ReadOnly Property Attributes() As String
                Get
                    Return Me.m_Attributes
                End Get
            End Property

#End Region

            ''' <summary>
            ''' Constructor.
            ''' </summary>
            ''' <param name="List">The response string from FTP LIST command.</param>
            ''' <remarks></remarks>
            Public Sub New(ByVal List As String)
                Dim Keys As New List(Of String)
                Dim items() As String = List.Split(Space(1))
                Dim item As String
                For Each item In items
                    If String.IsNullOrEmpty(item) = False Then
                        Keys.Add(item)
                    End If
                Next
                Me.Initialize(Keys.ToArray)
            End Sub

#Region " Provate Functions "

            ''' <summary>
            ''' Initialize the object from FTP LIST result string array.
            ''' </summary>
            ''' <param name="Keys">FTP LIST result string array.</param>
            ''' <remarks></remarks>
            Private Sub Initialize(ByVal Keys As String())
                'Set the attributes
                Me.InitializeItemKind(Keys(0))
                'Set owner user
                Me.m_User = Keys(2)
                'Set owner group
                Me.m_Group = Keys(3)
                'Set length
                Me.m_Length = CLng(Keys(4))
                'Set name
                Me.m_Name = Keys(Keys.Length - 1)
                'Set date
                Me.m_timeStamp = Me.GetDateString(Keys)
            End Sub

            ''' <summary>
            ''' Initialize item kind.
            ''' </summary>
            ''' <param name="Key">Item kind string from FTP LIST result string.</param>
            ''' <remarks></remarks>
            Private Sub InitializeItemKind(ByVal Key As String)
                Dim key0 As String = Key.Substring(0, 1)
                Dim key1 As String = Key.Substring(1, 3)
                Dim key2 As String = Key.Substring(4, 3)
                Dim key3 As String = Key.Substring(7, 3)
                'Set the attributes string
                Me.m_Attributes = key0 & key1 & key2 & key3
                'Set the directory or file attribute
                Me.m_Kind = IIf(String.Compare(key0, "d", True) = 0, FileSystemItemKind.Directory, FileSystemItemKind.File)
                Key = Key.Substring(1)
                'Set the access
                Me.m_accUsr = Me.GetAccess(key1)
                Me.m_accGrp = Me.GetAccess(key2)
                Me.m_accAll = Me.GetAccess(key3)
            End Sub

            ''' <summary>
            ''' Get the date in string format of file or directory.
            ''' </summary>
            ''' <param name="Keys">Date string array from FTP LIST result string.</param>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Private Function GetDateString(ByVal Keys() As String) As String
                'Dim sb As New System.Text.StringBuilder
                Dim year As Integer = Now.Year
                Dim ret As String = Keys(5) & Space(1) & Keys(6) & Space(1)
                'if is time then add the year
                If Keys(7).IndexOf(":") >= 0 Then
                    ret = ret & Me.GetYear(ret) & Space(1)
                End If
                ret = ret & Keys(7)
                Return ret
            End Function

            ''' <summary>
            ''' Get the year from Date string.
            ''' </summary>
            ''' <param name="strUnfinishedDate">Date string</param>
            ''' <returns></returns>
            ''' <remarks>The FTP date string may haven't year, this method add the year automaticly.</remarks>
            Private Function GetYear(ByVal strUnfinishedDate As String) As String
                Dim year As Integer = Now.Year
                Dim strDate As String = strUnfinishedDate & year
                Dim tm As DateTime = strDate
                If tm > Now Then
                    year = year - 1
                End If
                Return year.ToString
            End Function

            ''' <summary>
            ''' Get the access enum from FTP LIST result string.
            ''' </summary>
            ''' <param name="Key">Access string from FTP LIST result string.</param>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Private Function GetAccess(ByVal Key As String) As FileSystemItemAccess
                Dim ret As FileSystemItemAccess = FileSystemItemAccess.None
                'Read access
                If String.Compare(Key(0), "r", True) = 0 Then
                    ret = ret Or FileSystemItemAccess.Read
                End If
                'Write access
                If String.Compare(Key(1), "w", True) = 0 Then
                    ret = ret Or FileSystemItemAccess.Write
                End If
                'Execute access
                If String.Compare(Key(2), "x", True) = 0 Then
                    ret = ret Or FileSystemItemAccess.Execute
                End If
                Return ret
            End Function

#End Region

        End Class

#End Region

#Region " Shared Mehtods "

        ''' <summary>
        ''' Get the response stream from FtpWebResponse.
        ''' </summary>
        ''' <param name="rspn">FtpWebResponse object.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function GetStream(ByVal rspn As Net.FtpWebResponse) As IO.Stream
            Return rspn.GetResponseStream
        End Function

        ''' <summary>
        ''' Get the response stream from FtpWebRequest.
        ''' </summary>
        ''' <param name="reqs">FtpWebRequest object.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function GetStream(ByVal reqs As Net.FtpWebRequest) As IO.Stream
            Return reqs.GetRequestStream
        End Function

#End Region

        ''' <summary>
        ''' Constructor.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
            Me.m_UriBuilder = New UriBuilder
            Me.m_UriBuilder.Scheme = Uri.UriSchemeFtp
            Me.m_UriBuilder.Port = CST_URI_PORT
            'Me.m_Timeout = -1
        End Sub

        ''' <summary>
        ''' Constructor.
        ''' </summary>
        ''' <param name="Uri">Server Uri.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal Uri As Uri)
            Me.New()
            Me.m_UriBuilder = New UriBuilder(Uri)
        End Sub

        ''' <summary>
        ''' Constructor.
        ''' </summary>
        ''' <param name="Host">FTP server IP address.</param>
        ''' <param name="UserName">FTP server username.</param>
        ''' <param name="Password">FTP server password.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal Host As String, ByVal UserName As String, ByVal Password As String)
            Me.New()
            Me.m_UriBuilder.Host = Host
            Me.m_UriBuilder.UserName = UserName
            Me.m_UriBuilder.Password = Password
        End Sub

        ''' <summary>
        ''' Constructor.
        ''' </summary>
        ''' <param name="Host">FTP server IP address.</param>
        ''' <param name="Port">FTP server port.</param>
        ''' <param name="UserName">FTP server username.</param>
        ''' <param name="Password">FTP server password.</param>
        ''' <param name="Path">Initialize path after login.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal Host As String, ByVal Port As Integer, ByVal UserName As String, ByVal Password As String, ByVal Path As String)
            Me.New(Host, UserName, Password)
            Me.m_UriBuilder.Port = Port
            Me.m_UriBuilder.Path = Path
        End Sub

#Region " Public Methods "

        ''' <summary>
        ''' Move to the parent directory.
        ''' </summary>
        ''' <remarks>If the directory is the top level of current user, it will not be moved.</remarks>
        Public Sub CDUP()
            Dim lastPos As Integer
            If Me.m_UriBuilder.Path.Length > 1 Then
                'Remove the last "/"
                Me.m_UriBuilder.Path = Me.m_UriBuilder.Path.Remove(Me.m_UriBuilder.Path.Length - 2)
                'Get the last "/" to devide the last directory
                lastPos = Me.m_UriBuilder.Path.LastIndexOf(Common.Variants.DIV)
                If lastPos > 0 Then
                    Me.m_UriBuilder.Path = Me.m_UriBuilder.Path.Remove(lastPos + 1)
                Else
                    Me.m_UriBuilder.Path = String.Empty
                End If
            End If
        End Sub

        ''' <summary>
        ''' Move into the directory.
        ''' </summary>
        ''' <param name="DirectoryName">Directory to move.</param>
        ''' <remarks></remarks>
        Public Sub CDIN(ByVal DirectoryName As String)
            Me.m_UriBuilder.Path = Me.m_UriBuilder.Path & DirectoryName & Common.Variants.DIV
        End Sub

        ''' <summary>
        ''' Move into the directory.
        ''' </summary>
        ''' <param name="fsi">File System Item object to move in.</param>
        ''' <remarks></remarks>
        Public Sub CDIN(ByVal fsi As FileSystemItem)
            If fsi.Kind = FileSystemItemKind.Directory Then
                Me.CDIN(fsi.Name)
            End If
        End Sub

        ''' <summary>
        ''' Download the file in current path.
        ''' </summary>
        ''' <param name="FileName">The fileanee to download.</param>
        ''' <param name="UseBinary">Set if use binary mode to download or not.</param>
        ''' <returns>The file response.</returns>
        ''' <remarks>
        ''' To get the file context, use GetStream function to get the stream of FtpWebResponse.
        ''' After finish using it, close both stream and FtpWebResponse.
        ''' </remarks>
        Public Function Download(ByVal FileName As String, ByVal UseBinary As Boolean) As Net.FtpWebResponse
            Return Me.GetResponse(Net.WebRequestMethods.Ftp.DownloadFile, FileName, UseBinary, )
        End Function

        ''' <summary>
        ''' Download the file in current path and file name.
        ''' </summary>
        ''' <param name="UseBinary">Set if use binary mode to download or not.</param>
        ''' <returns>The file response.</returns>
        ''' <remarks>
        ''' To get the file context, use GetStream function to get the stream of FtpWebResponse.
        ''' After finish using it, close both stream and FtpWebResponse.
        ''' </remarks>
        Public Function Download(ByVal UseBinary As Boolean) As Net.FtpWebResponse
            Return Me.GetResponse(Net.WebRequestMethods.Ftp.DownloadFile, , UseBinary, )
        End Function

        ''' <summary>
        ''' Upload the file in current path.
        ''' </summary>
        ''' <param name="stm">The stream to upload.</param>
        ''' <param name="FileName">The filename to upload.</param>
        ''' <param name="UseBinary">Set if use binary mode to download or not.</param>
        ''' <remarks></remarks>
        Public Sub Upload(ByVal stm As IO.Stream, ByVal FileName As String, ByVal UseBinary As Boolean)
            Dim uploadResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.UploadFile, FileName, UseBinary, stm)
            Me.CloseResponse(uploadResponse)
        End Sub

        ''' <summary>
        ''' Upload the file in current path and current file name.
        ''' </summary>
        ''' <param name="stm">The stream to upload.</param>
        ''' <param name="UseBinary">Set if use binary mode to download or not.</param>
        ''' <remarks></remarks>
        Public Sub Upload(ByVal stm As IO.Stream, ByVal UseBinary As Boolean)
            Dim uploadResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.UploadFile, , UseBinary, stm)
            Me.CloseResponse(uploadResponse)
        End Sub

        ''' <summary>
        ''' Get the file or directory size.
        ''' </summary>
        ''' <param name="FileName">The filename to get the size.</param>
        ''' <returns>The size of the file.</returns>
        ''' <remarks></remarks>
        Public Function GetFileSize(ByVal FileName As String) As Long
            Dim ret As Long = 0
            Dim sizeResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.GetFileSize, FileName, , )
            If sizeResponse.StatusCode = Net.FtpStatusCode.FileStatus Then
                ret = CLng(sizeResponse.StatusDescription.Split(Space(1))(1))
            End If
            Me.CloseResponse(sizeResponse)
            Return ret
        End Function

        ''' <summary>
        ''' Get the file or directory size.
        ''' </summary>
        ''' <returns>The size of the file.</returns>
        ''' <remarks></remarks>
        Public Function GetFileSize() As Long
            Dim ret As Long = 0
            Dim sizeResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.GetFileSize, , , )
            If sizeResponse.StatusCode = Net.FtpStatusCode.FileStatus Then
                ret = CLng(sizeResponse.StatusDescription.Split(Space(1))(1))
            End If
            Me.CloseResponse(sizeResponse)
            Return ret
        End Function

        ''' <summary>
        ''' Get the file or directory last modified time stamp.
        ''' </summary>
        ''' <param name="FileName">The filename to get the date.</param>
        ''' <returns>The last modified time stamp of the file.</returns>
        ''' <remarks></remarks>
        Public Function GetFileDate(ByVal FileName As String) As Date
            Dim ret As Date = Date.MinValue
            Dim dateResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.GetDateTimestamp, FileName, , )
            If dateResponse.StatusCode = Net.FtpStatusCode.FileStatus Then
                ret = dateResponse.LastModified
            End If
            Return ret
        End Function

        ''' <summary>
        ''' Get the file or directory last modified time stamp.
        ''' </summary>
        ''' <returns>The last modified time stamp of the file.</returns>
        ''' <remarks></remarks>
        Public Function GetFileDate() As Date
            Dim ret As Date = Date.MinValue
            Dim dateResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.GetDateTimestamp, , , )
            If dateResponse.StatusCode = Net.FtpStatusCode.FileStatus Then
                ret = dateResponse.LastModified
            End If
            Return ret
        End Function

        ''' <summary>
        ''' Delete the file or directory.
        ''' </summary>
        ''' <param name="FileName">The filename to delete.</param>
        ''' <remarks></remarks>
        Public Sub Delete(ByVal FileName As String)
            Dim deleteResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.DeleteFile, FileName, , )
            Me.CloseResponse(deleteResponse)
        End Sub

        ''' <summary>
        ''' Delete the file or directory.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Delete()
            Dim deleteResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.DeleteFile, , , )
            Me.CloseResponse(deleteResponse)
        End Sub

        ''' <summary>
        ''' Make a new directory in current path.
        ''' </summary>
        ''' <param name="DirectoryName">Directory name to be created.</param>
        ''' <remarks></remarks>
        Public Sub MakeDirectory(ByVal DirectoryName As String)
            Dim mkdirResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.MakeDirectory, DirectoryName, , )
            Me.CloseResponse(mkdirResponse)
        End Sub

        ''' <summary>
        ''' Get the file or directory is existed.
        ''' </summary>
        ''' <param name="FileName">The file or directory name</param>
        ''' <returns>The file or directory is existed or not</returns>
        ''' <remarks></remarks>
        Public Function IsExist(ByVal FileName As String) As Boolean
            Dim ret As Boolean
            Try
                Me.GetFileSize(FileName)
                ret = True
            Catch ex As Exception
                ret = False
            End Try
            Return ret
        End Function

        ''' <summary>
        ''' Get the file or directory is existed.
        ''' </summary>
        ''' <returns>The file or directory is existed or not</returns>
        ''' <remarks></remarks>
        Public Function IsExist() As Boolean
            Dim ret As Boolean
            Try
                Me.GetFileSize()
                ret = True
            Catch ex As Exception
                ret = False
            End Try
            Return ret
        End Function

        Public Function Rename(ByVal FileName As String, ByVal NewFileName As String) As Boolean
            Dim rnResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.Rename, FileName, , , NewFileName)
            Me.CloseResponse(rnResponse)
        End Function

        Public Function Rename(ByVal NewFileName As String) As Boolean
            Dim rnResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.Rename, , , , NewFileName)
            Me.CloseResponse(rnResponse)
        End Function

#End Region

#Region " Private Methods "

        ''' <summary>
        ''' Get the path string.
        ''' </summary>
        ''' <returns>Path string.</returns>
        ''' <remarks></remarks>
        Private Function GetPathString() As String
            Dim fullString, path As String
            Dim firstMark, lastMark As Integer
            Dim listResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.PrintWorkingDirectory, , , )
            If listResponse.StatusCode = Net.FtpStatusCode.PathnameCreated Then
                fullString = listResponse.StatusDescription
                firstMark = fullString.IndexOf(Chr(34))
                lastMark = fullString.LastIndexOf(Chr(34))
                path = fullString.Substring(firstMark + 1, lastMark - firstMark - 1)
            Else
                path = String.Empty
            End If
            Me.CloseResponse(listResponse)
            Return path
        End Function

        ''' <summary>
        ''' Get File System Items in current path.
        ''' </summary>
        ''' <returns>File System Items in current path.</returns>
        ''' <remarks></remarks>
        Private Function GetFileItems() As List(Of FileSystemItem)
            Dim info As String
            Dim blnIsFirst As Boolean = True
            Dim fsis As New List(Of FileSystemItem)
            Dim listResponse As Net.FtpWebResponse = Me.GetResponse(Net.WebRequestMethods.Ftp.ListDirectoryDetails, , , )
            Using sr As New IO.StreamReader(listResponse.GetResponseStream, Common.Methods.GetCurrentEncoding)
                While sr.Peek > -1
                    info = sr.ReadLine
                    If blnIsFirst = True Then
                        blnIsFirst = False
                    Else
                        fsis.Add(New FileSystemItem(info))
                    End If
                End While
            End Using
            Me.CloseResponse(listResponse)
            Return fsis
        End Function

        ''' <summary>
        ''' Get the response object from FTP request.
        ''' </summary>
        ''' <param name="Method">FTP protocol method string.</param>
        ''' <param name="FileName">Operating file or directory name.</param>
        ''' <param name="UseBinary">Set if use binary mode to download or not.</param>
        ''' <param name="stm">The request stream.</param>
        ''' <returns>Response object answer the FTP request.</returns>
        ''' <remarks></remarks>
        Private Function GetResponse(ByVal Method As String, Optional ByVal FileName As String = "", Optional ByVal UseBinary As Boolean = True, Optional ByVal stm As IO.Stream = Nothing, Optional ByVal RenameTo As String = "") As Net.FtpWebResponse
            Dim req As Net.FtpWebRequest = Net.FtpWebRequest.Create(New Uri(Me.m_UriBuilder.Uri, FileName))
            req.KeepAlive = False
            req.UseBinary = UseBinary
            req.Timeout = IIf(m_Timeout > 0, m_Timeout * 1000, -1)
            req.Method = Method
            req.UsePassive = True
            If String.IsNullOrEmpty(RenameTo) = False Then
                req.RenameTo = RenameTo
            End If
            'req.Proxy = Net.WebRequest.DefaultWebProxy
            If stm IsNot Nothing Then
                Dim buffer(1024) As Byte
                Dim bytesRead As Integer
                Using requestStream As IO.Stream = req.GetRequestStream
                    While True
                        bytesRead = stm.Read(buffer, 0, buffer.Length)
                        If bytesRead = 0 Then
                            Exit While
                        End If
                        requestStream.Write(buffer, 0, bytesRead)
                    End While
                    requestStream.Close()
                End Using
            End If
            Return req.GetResponse
        End Function

        ''' <summary>
        ''' Close the response.
        ''' </summary>
        ''' <param name="listResponse">Response to close.</param>
        ''' <remarks></remarks>
        Private Sub CloseResponse(ByVal listResponse As Net.FtpWebResponse)
            listResponse.Close()
        End Sub

#End Region

    End Class

End Namespace
